﻿using Loong.Admin.Security.Authentication.JwtBearer;
using Loong.Admin.Text.Normalization;
using Loong.Admin.Users;
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Volo.Abp.Security.Claims;

namespace Loong.Admin.Account
{
    public class AccountAppService : AdminAppService, IAccountAppService
    {
        private readonly ILookupNormalizer _lookupNormalizer;
        private readonly JwtHandler _jwtHandler;
        private readonly AccountManager _accountManager;
        private readonly IUserRepository _userRepository;

        public AccountAppService(
            ILookupNormalizer lookupNormalizer,
            JwtHandler jwtHandler,
            AccountManager accountManager,
            IUserRepository userRepository)
        {
            _lookupNormalizer = lookupNormalizer;
            _jwtHandler = jwtHandler;
            _accountManager = accountManager;
            _userRepository = userRepository;
        }

        public async Task<LoginResult> LoginAsync(LoginInput input)
        {
            var normalizedIdentifier = _lookupNormalizer.Normalize(input.Identifier);
            var user = await _userRepository.FindAsync(u =>
                u.NormalizedUserName == normalizedIdentifier ||
                u.NormalizedEmail == normalizedIdentifier ||
                u.PhoneNumber == input.Identifier);

            var signInResult = await _accountManager.SignInAsync(user, input.Password);

            var loginResult = new LoginResult
            {
                Result = signInResult,
                Message = signInResult.ToString()
            };
            if (signInResult == SignInResult.Success)
            {
                loginResult.AccessToken = _jwtHandler.CreateJwtToken(CreateUserIdentity(user!));
            }

            return loginResult;
        }

        private static ClaimsIdentity CreateUserIdentity(User user)
        {
            var identity = new ClaimsIdentity();
            identity.AddClaim(new Claim(AbpClaimTypes.UserId, user.Id.ToString()));
            identity.AddClaim(new Claim(AbpClaimTypes.UserName, user.UserName));
            identity.AddClaim(new Claim(AbpClaimTypes.Email, user.Email));
            identity.AddClaim(new Claim(AbpClaimTypes.Role, "admin"));
            if (!user.PhoneNumber.IsNullOrWhiteSpace())
            {
                identity.AddClaim(new Claim(AbpClaimTypes.PhoneNumber, user.PhoneNumber));
            }
            identity.AddClaim(new Claim(AdminClaimTypes.SecurityStamp, user.SecurityStamp));
            if (user.TenantId.HasValue)
            {
                identity.AddClaim(new Claim(AbpClaimTypes.TenantId, user.TenantId.Value.ToString()));
            }

            return identity;
        }
    }
}